import { Op, literal, fn } from 'sequelize';
import { models } from '../../db';
import type { UserInfo, UserArraying, UserRole, UserEquip, UserGoods } from '../types';

const {
  config_hero: ConfigHeroModel,
  config_equip: ConfigEquipModel,
  config_talent: ConfigTalentModel,
  config_shop: ConfigShopModel,
  config_vip: ConfigVipModel,
  user: UserModel,
  user_hero: UserHeroModel,
  user_equip: UserEquipModel,
  user_item: UserItemModel,
  user_log_assets: UserLogAssetsModel,
} = models;

export const initUserInfo = (user_id: string) => {
  return new Promise(async (resolve, reject) => {
    const acc = await getUserInfo(user_id);
    const arraying = await getUserArring(user_id);
    const role = await getUserRole(user_id);
    const equip = await getUserEquip(user_id);
    const goods = await getUserGoods(user_id);
    const shop = await getUserShop(user_id);

    return resolve({ acc, arraying, role, equip, goods, shop });
  });
};

export const getUserInfo = (user_id: string) => {
  try {
    return new Promise(async (resolve, reject) => {
      const user = await UserModel.findOne({ where: { id: user_id } });

      if (!user) {
        return reject('用户不存在');
      }

      const { name, level, exp, gold, silver, honor, vip, power, sponsor } = user.dataValues;

      const res: UserInfo = {
        name,
        level,
        exp,
        gold,
        silver,
        vip,
        sponsor,
        power,
        honor,
      };
      return resolve(res);
    });
  } catch (error) {
    console.log(error);
  }
};

export const getUserArring = (user_id: string) => {
  return new Promise(async (resolve, reject) => {
    const userHeros = await UserHeroModel.findAll({
      where: { user_id, position_x: { [Op.ne]: 0 }, position_y: { [Op.ne]: 0 } },
    });
    const res: UserArraying[] = [];

    for (const item of userHeros) {
      const { id, hero_id, position_x, position_y } = item.dataValues;
      res.push({
        id: id,
        heroId: hero_id,
        position: [position_x, position_y],
      });
    }
    return resolve(res);
  });
};

export const getUserRole = (user_id: string): Promise<UserRole[]> => {
  return new Promise(async (resolve, reject) => {
    const res: UserRole[] = [];
    // 定义关联关系
    UserHeroModel.belongsTo(ConfigHeroModel, { foreignKey: 'hero_id' });
    const userRoles = await UserHeroModel.findAll({
      where: { user_id },
      include: [
        {
          model: ConfigHeroModel,
        },
      ],
      order: [
        [
          literal(
            `CASE WHEN position_x IN (1, 2, 3) THEN 1 WHEN position_x IN (4, 5, 6) THEN 2 ELSE 3 END`,
          ),
          'ASC',
        ],
        [{ model: ConfigHeroModel, as: 'config_hero' }, 'rarity', 'DESC'],
        [{ model: ConfigHeroModel, as: 'config_hero' }, 'id', 'ASC'],
      ],
    });
    if (!userRoles) {
      return resolve(res);
    }

    // 查一次表，拿到所有上阵英雄的映射id
    const arrayingHeroIds = userRoles
      .filter(item => item.dataValues.position_x !== 0 && item.dataValues.position_y !== 0)
      .map(item => item.dataValues.hero_id);
    // 查一次表，拿到所有被使用的装备
    UserEquipModel.belongsTo(ConfigEquipModel, { foreignKey: 'equip_id' });
    const useEquipM = await UserEquipModel.findAll({
      where: { user_id, hero_id: { [Op.ne]: null } },
      include: [
        {
          model: ConfigEquipModel,
        },
      ],
    });

    const useEquipIds: Record<string, any>[] = useEquipM.map(item => {
      return {
        id: item.dataValues.id,
        level: item.dataValues.level,
        equipId: item.dataValues.equip_id,
        equipConfig: item.dataValues.config_equip.dataValues,
      };
    });

    for (const item of userRoles) {
      const {
        id,
        hero_id,
        level,
        exp,
        position_x,
        position_y,
        equip1,
        equip2,
        equip3,
        equip4,
        config_hero,
      } = item.dataValues;
      const base = config_hero.dataValues;
      const equips = [equip1, equip2, equip3, equip4];
      const talents = await calcRoleTalent(
        arrayingHeroIds,
        useEquipIds,
        base,
        equips.filter(item => item !== null),
      );

      const attrs = calcRoleAttr(level, base, useEquipIds, equips, talents.resAttr);

      res.push({
        id: id,
        heroId: hero_id,
        heroName: config_hero.dataValues.name,
        heroAvatar: config_hero.dataValues.avatar,
        level: level,
        exp: exp,
        position: [position_x, position_y],
        equip: equips,
        talent: talents.res,
        skill1: base.skill1,
        skill2: base.skill2,
        skill3: base.skill3,
        ...attrs,
      });
    }
    return resolve(res);
  });
};

export const getUserEquip = (user_id: string) => {
  return new Promise(async (resolve, reject) => {
    const res: UserEquip[] = [];
    // 定义关联关系
    UserEquipModel.belongsTo(ConfigEquipModel, { foreignKey: 'equip_id' });

    const userEquips = await UserEquipModel.findAll({
      where: { user_id },
      include: [
        {
          model: ConfigEquipModel,
        },
      ],
      order: [
        ['hero_id', 'DESC'],
        [{ model: ConfigEquipModel, as: 'config_equip' }, 'rarity', 'DESC'],
        [{ model: ConfigEquipModel, as: 'config_equip' }, 'type'],
      ],
    });
    if (!userEquips) {
      return resolve(res);
    }
    for (const item of userEquips) {
      const { id, equip_id, hero_id, level, exp, config_equip } = item.dataValues;
      const base = config_equip.dataValues;
      res.push({
        id: id,
        heroId: hero_id,
        equipId: equip_id,
        level,
        exp,
        type: base.type,
        ...calcEquipAttr(level, base),
      });
    }
    return resolve(res);
  });
};

export const getUserGoods = (user_id: string) => {
  return new Promise(async (resolve, reject) => {
    const res: UserGoods[] = [];
    const userGoods = await UserItemModel.findAll({
      where: { user_id, count: { [Op.gt]: 0 } },
      order: [['item_id', 'ASC']],
    });

    if (!userGoods) {
      return resolve(res);
    }

    for (const item of userGoods) {
      const { id, item_id, count } = item.dataValues;

      res.push({
        id: id,
        goodsId: item_id,
        count: count,
      });
    }

    return resolve(res);
  });
};

export const getUserShop = (user_id: string) => {
  return new Promise(async (resolve, reject) => {
    // 获取应得次数
    const shopGoods = await ConfigShopModel.findAll();
    const allShop = shopGoods.map(item => {
      return {
        id: item.dataValues.item_id,
        count: item.dataValues.count,
        control: item.dataValues.control,
        control_field: item.dataValues.control_field,
      };
    });

    // 用户可购买次数
    UserModel.belongsTo(ConfigVipModel, { foreignKey: 'vip' });
    const userCanGet = await UserModel.findOne({
      where: { id: user_id },
      include: [
        {
          model: ConfigVipModel,
        },
      ],
    });
    const vipInfo = userCanGet?.dataValues.config_vip?.dataValues;

    const userAlreadyGet = await UserLogAssetsModel.findAll({
      where: {
        user_id,
        assets_type: 'item',
        type: 'get',
        reason_type: 'shop',
        createdAt: {
          [Op.gte]: new Date().setHours(0, 0, 0, 0),
          [Op.lt]: new Date().setHours(23, 59, 59, 999),
        },
      },
    });

    const result = userAlreadyGet.reduce((acc: Record<string, any>, current) => {
      const assetsId = current.dataValues.assets_id;
      if (!acc[assetsId]) {
        acc[assetsId] = 0;
      }
      acc[assetsId] += current.dataValues.count;
      return acc;
    }, {});

    const assetsIds = Object.keys(result);

    const userItems = await UserItemModel.findAll({
      where: {
        id: {
          [Op.in]: assetsIds,
        },
      },
    });

    const itemIdMap: Record<string, any> = {};

    userItems.forEach(userItem => {
      itemIdMap[userItem.dataValues.id] = userItem.dataValues.item_id;
    });

    const userShopInfo: Record<string, any>[] = [];

    for (const key in result) {
      userShopInfo.push({
        id: itemIdMap[key],
        count: result[key],
      });
    }

    // 获取购买次数
    for (let i = 0; i < allShop.length; i++) {
      const item = allShop[i];
      if (item.control === 0) {
        continue;
      }

      const alreadyGet = userShopInfo.find((info: any) => info.id === item.id);

      if (alreadyGet) {
        item.count = vipInfo[item.control_field] - alreadyGet.count || 0;
      } else {
        item.count = vipInfo[item.control_field] || 0;
      }
    }
    // 获取可购买次数
    return resolve(
      allShop
        .filter(item => item.count > 0)
        .map(item => {
          return {
            id: item.id,
            count: item.count,
          };
        }),
    );
  });
};
export const changeName = (user_id: string, data: Record<string, any>) => {
  return new Promise(async (resolve, reject) => {
    try {
      const { text } = data;
      const newName = text.trim();

      if (newName.length === 0) {
        return;
      }

      if (newName.length > 14) {
        return reject('名字太长了');
      }

      await UserModel.update(
        { name: newName },
        {
          where: { id: user_id },
        },
      );

      return resolve('ok');
    } catch (error) {
      console.log(error);
    }
  });
};

// 临时代码
const calcRoleAttr = (
  level: number,
  base: Record<string, any>,
  useEquipIds: Record<string, any>[],
  equips: string[] | null[],
  resAttr: Record<string, any>,
) => {
  // 计算成长属性
  const baseAttr = getBaseAttr(level, base);

  const equipAttr = {
    hp: 0,
    attack: 0,
    defence: 0,
    speed: 0,
  };

  // 计算装备属性
  for (let i = 0; i < 4; i++) {
    const equipId = equips[i];
    if (!equipId) {
      continue;
    }

    const equip = useEquipIds.find(item => item.id === equipId);

    if (!equip) {
      continue;
    }

    const equipItemAttr = getBaseAttr(equip.level, equip.equipConfig);
    equipAttr.hp += equipItemAttr.hp;
    equipAttr.attack += equipItemAttr.attack;
    equipAttr.defence += equipItemAttr.defence;
    equipAttr.speed += equipItemAttr.speed;
  }

  // 合并属性
  const totalAttr = {
    hp: baseAttr.hp + equipAttr.hp,
    attack: baseAttr.attack + equipAttr.attack,
    defence: baseAttr.defence + equipAttr.defence,
    speed: baseAttr.speed + equipAttr.speed,
  };

  // 计算添加协作属性后的最终值
  const finalAttr = {
    hp: Math.round((totalAttr.hp * resAttr.hp) / 100),
    attack: Math.round((totalAttr.attack * resAttr.attack) / 100),
    defence: Math.round((totalAttr.defence * resAttr.defence) / 100),
    speed: Math.round((totalAttr.speed * resAttr.speed) / 100),
  };

  return finalAttr;
};

const calcEquipAttr = (level: number, base: Record<string, any>) => {
  return getBaseAttr(level, base);
};

const getBaseAttr = (level: number, base: Record<string, any>) => {
  const { hp, attack, defence, speed } = base;
  return {
    hp: hp + (hp / 10) * (level - 1),
    attack: attack + (attack / 10) * (level - 1),
    defence: defence + (defence / 10) * (level - 1),
    speed: speed + (speed / 10) * (level - 1),
  };
};

const calcRoleTalent = async (
  arrayingHeroIds: number[],
  useEquipIds: Record<string, any>[],
  base: Record<string, any>,
  equips: string[] | null[],
) => {
  const res: number[] = [];
  const resAttr: Record<string, any> = {
    hp: 100,
    attack: 100,
    defence: 100,
    speed: 100,
  };
  // 获得当前英雄的协作信息
  const { talent1, talent2, talent3, talent4, talent5, talent6 } = base;
  const talentIds: number[] = [talent1, talent2, talent3, talent4, talent5, talent6];
  const talentInfo: Record<string, any> = (
    await ConfigTalentModel.findAll({ where: { id: talentIds } })
  ).map(item => item.dataValues);

  // 映射出当前武将的装备对应的config_equip_id
  const equipRealIds: number[] = [];
  equips.forEach(v => {
    const { equipId } = useEquipIds.find(item => item.id === v)!;
    equipRealIds.push(equipId);
  });

  // 开始检查卡牌的协作
  for (let i = 0; i < talentInfo.length; i++) {
    const talent = talentInfo[i];

    if (talent.id === 0) {
      continue;
    }

    // 协作状态
    let talentActivate = false;

    for (let j = 1; j <= 6; j++) {
      const talentCo = talent[`co${j}`];
      // 英雄协作
      if (talentCo > 0 && talentCo < 20000) {
        const role = arrayingHeroIds.find((v: number) => v === talentCo);
        if (!role) {
          break;
        }
      }

      if (talentCo > 20000) {
        // 当前武将没有携带装备
        if (equipRealIds.length === 0) {
          break;
        }

        const define = equipRealIds.find(v => v === talentCo);

        if (define) {
          talentActivate = true;
        }
        break;
      }

      // 走到这里就说明6条都满足了
      if (j === 6) {
        talentActivate = true;
      }
    }

    if (talentActivate) {
      res.push(talent.id);
      if (talent.talent === 1) {
        resAttr.hp += talent.value;
      } else if (talent.talent === 2) {
        resAttr.attack += talent.value;
      } else if (talent.talent === 3) {
        resAttr.defence += talent.value;
      } else if (talent.talent === 4) {
        resAttr.speed += talent.value;
      }
    }
  }
  return { res, resAttr };
};
